home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 July: Mac OS SDK / Dev.CD Jul 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Applications… / QuickDraw GX Aware Sample ƒ / Simple Sample GX ƒ / menus & windows.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-20  |  24.8 KB  |  975 lines  |  [TEXT/MMCC]

  1. /*********************************************************************
  2.  
  3.     menus & windows.c
  4.     
  5.     This file contains the menu and window handling code for the
  6.     QuickDraw GX aware sample, "Simple Sample GX."
  7.     
  8.     Additional info can be found in the related develop #19 article,
  9.     "Adding QuickDraw GX Printing to QuickDraw Applications."
  10.  
  11.     Dave Hersey, Apple Developer Technical Support.
  12.     
  13.     ——————— Edit Trail ———————
  14.     
  15.     constructed:                                    1/22/94  - dmh
  16.     cleaned up for 2nd draft of develop article:    3/10/94  - dmh
  17.     cleaned up for final:                            4/14/94  - dmh
  18.     removed sprintf calls, to avoid need for ANSI   8/16/94  - nick
  19.     added NewGXPrintingEventProc to build 
  20.     descriptors for ppc                             8/17/94  - nick
  21.     universalized:                                    8/25/94  - dmh
  22.  
  23. *********************************************************************/
  24.  
  25. #include "Simple Sample.h"
  26.  
  27.  
  28. /************************************************************
  29.   MyCreateDocument - This routine is called to create a new
  30.   document.
  31.  
  32. *************************************************************/
  33.  
  34. OSErr MyCreateDocument(char *docTitle, MyDocumentPtr *createdDocument)
  35. {
  36.     OSErr            err;
  37.     WindowPtr        documentWindow;
  38.     long            newPage;
  39.  
  40.     *createdDocument = nil;
  41.  
  42. // Create a window for our document.
  43.  
  44.     documentWindow = (WindowPtr) NewCWindow(nil, &gWindowRect, (ConstStr255Param) docTitle, false, noGrowDocProc, (WindowPtr)-1L, true, 0L);
  45.     require_action(documentWindow, CouldNotCreateWindow, err = MemError(););
  46.  
  47. // Initialize our private data for the document.
  48.  
  49.     *createdDocument = (MyDocumentPtr) NewPtrClear(sizeof(MyDocumentRec));
  50.     require_action(*createdDocument, CouldNotCreateDocRec, err = MemError(););
  51.  
  52. /*
  53.     If QuickDraw GX is present, create a new job object and install an application
  54.     override for the gxPrintingEvent message.  Note that you only need to have
  55.     this message overridden while print dialogs are displayed, but overriding it
  56.     here doesn't hurt.
  57.     
  58.     If QuickDraw GX is not present, simply create a print handle.
  59. */
  60.  
  61.     if (gGXIsPresent)
  62.     {
  63.         err = GXNewJob(&(*createdDocument)->documentJob);
  64.  
  65.         if (err == noErr)
  66.             GXInstallApplicationOverride((*createdDocument)->documentJob,
  67.                                          gxPrintingEventMsg,
  68.                                          NewGXPrintingEventProc(MyPrintingEventOverride));
  69.     }
  70.     else
  71.     {
  72.         (*createdDocument)->documentPrintHdl = (THPrint) NewHandle(sizeof(TPrint));
  73.         err = MemError();
  74.  
  75.         if (!err)
  76.         {
  77.             PrOpen();
  78.             PrintDefault((*createdDocument)->documentPrintHdl);
  79.             PrClose();
  80.         }
  81.     }
  82.  
  83. /*
  84.     If there were no errors, add 1 page to the document, and
  85.     store a reference to our private data in the document's
  86.     window's refCon field.
  87. */
  88.  
  89.     nrequire(err, CouldNotCreatePrintStuff);
  90.     
  91.     (*createdDocument)->numPages = 0;
  92.     (*createdDocument)->documentWindow = documentWindow;
  93.     (*createdDocument)->documentFSSpec.name[0] = 0;        // Indicates that document has never
  94.                                                         // been saved.
  95.     if (docTitle[0] > 31)
  96.         docTitle[0] = 31;
  97.     
  98.     BlockMove(&docTitle[0], &(*createdDocument)->documentTitle[0], (long) docTitle[0] +1);
  99.     newPage = 0;
  100.     err = MyInsertPage(*createdDocument, &newPage);
  101.     (*createdDocument)->curPage = newPage;
  102.  
  103. // Set the refCon to point to our document info structure.
  104.  
  105.     nrequire(err, CouldNotInsertPage);
  106.     SetWRefCon(documentWindow, (long) *createdDocument);
  107.     require(err, NoProblems);
  108.  
  109. CouldNotInsertPage:
  110.     if (gGXIsPresent)
  111.         GXDisposeJob((*createdDocument)->documentJob);
  112.     else
  113.         DisposHandle((Handle) (*createdDocument)->documentPrintHdl);
  114.  
  115. CouldNotCreatePrintStuff:
  116.     DisposePtr((Ptr) *createdDocument);
  117.  
  118. CouldNotCreateDocRec:
  119.     DisposeWindow(documentWindow);
  120.  
  121. CouldNotCreateWindow:
  122. NoProblems:
  123.     return err;
  124. }
  125.  
  126.  
  127. /************************************************************
  128.   MyDisposeDocument - This routine is called when we need to
  129.   dispose of a window.
  130.  
  131. *************************************************************/
  132.  
  133. void MyDisposeDocument(MyDocumentPtr whichDocument)
  134. {
  135.     long        numPages, pg;
  136.     
  137. // Dispose of our private data for each page of this document.
  138.  
  139.     numPages = whichDocument->numPages;
  140.  
  141.     for (pg = numPages; pg >= 1; pg--)
  142.         MyDisposePage(whichDocument, pg);
  143.  
  144. /*
  145.     Dispose of our document's print record and job object,
  146.     if any.  Finally dispose of the document's window and
  147.     the pointer to our document's private data.
  148. */
  149.     if (whichDocument->documentPrintHdl != nil)
  150.         DisposHandle((Handle) whichDocument->documentPrintHdl);
  151.     
  152.     if (whichDocument->documentJob != nil)
  153.         GXDisposeJob(whichDocument->documentJob);
  154.  
  155.        DisposeWindow(whichDocument->documentWindow);
  156.     DisposePtr((Ptr) whichDocument);
  157. }
  158.  
  159.  
  160. /************************************************************
  161.   MyInsertPage - This routine is called when we need to add
  162.   a page to a document.  The page is added AFTER the page
  163.   number passed (1-based).  If whichPg is greater than the
  164.   last page of the document, the new page is added to the
  165.   end of the document.  If whichPg is less than 1, the page
  166.   is added to the beginning of the doc.  The page number of
  167.   the new page is returned in whichPg.
  168.  
  169. *************************************************************/
  170.  
  171. OSErr MyInsertPage(MyDocumentPtr whichDocument, long *whichPage)
  172. {
  173.     OSErr        err = noErr;
  174.     long        numPages;
  175.  
  176. // Pin the number of the page to add to the range (1, numPages +1).
  177.  
  178.     numPages = whichDocument->numPages;
  179.     *whichPage = (*whichPage < 1)? 1: (*whichPage < numPages)? *whichPage +1: numPages +1;
  180.  
  181. /*
  182.     If QuickDraw GX is present, set this page's format to nil so
  183.     that we use the default job format.
  184. */
  185.     if (gGXIsPresent)
  186.         whichDocument->pageFormat[*whichPage -1] = nil;
  187.  
  188. /*
  189.     Do whatever you need to do to add page data here.
  190.     .
  191.     .
  192.     .
  193.     
  194. */
  195.  
  196.     numPages = ++whichDocument->numPages;
  197.     return err;
  198. }
  199.  
  200.  
  201. /************************************************************
  202.   MyDisposePage - This routine is called when we need to
  203.   dispose of a page in a document.
  204.  
  205. *************************************************************/
  206.  
  207. void MyDisposePage(MyDocumentPtr whichDocument, long whichPage)
  208. {
  209.     long        numPages;
  210.  
  211. // Idiot control.
  212.  
  213.     if (whichPage > whichDocument->numPages) return;    // ?!  There aren't that many pages!!
  214.     if (whichPage < 1) return;                            // ?!  Page numbers start at 1!!
  215.  
  216. /*
  217.     If GX is present and we have a page format for this
  218.     page, dispose of the format.
  219. */
  220.     if (gGXIsPresent && (whichDocument->pageFormat[whichPage -1] != nil))
  221.         GXDisposeFormat(whichDocument->pageFormat[whichPage -1]);
  222.  
  223. /*
  224.     Do whatever you need to do to remove page data here.
  225.     .
  226.     .
  227.     .
  228.     
  229. */
  230.  
  231. // We now have one less page in our document.
  232.  
  233.     numPages = --whichDocument->numPages;
  234. }
  235.  
  236.  
  237. /************************************************************
  238.   MyUpdateWindow - This routine simply updates the passed
  239.   window.
  240.  
  241. *************************************************************/
  242.  
  243. void MyUpdateWindow(WindowPtr whichWindow)
  244. {
  245.     GrafPtr        oldPort;
  246.  
  247. // Update the indicated window.
  248.  
  249.     if (((WindowPeek) whichWindow)->windowKind == userKind)
  250.     {
  251.         GetPort(&oldPort);
  252.         SetPort(whichWindow);
  253.         BeginUpdate(whichWindow);
  254.         MyDrawContents(whichWindow);
  255.         EndUpdate(whichWindow);
  256.         SetPort(oldPort);
  257.     }
  258. }
  259.  
  260.  
  261. /************************************************************
  262.   MyDrawContents - This routine draws the contents of a
  263.   window.  Note that this same code is used to draw during
  264.   printing.  All we do in this code is make a bunch of
  265.   QuickDraw calls to draw our document's pages.
  266.  
  267. *************************************************************/
  268.  
  269. void MyDrawContents(WindowPtr whichWindow)
  270. {
  271.     MyDocumentPtr    windowDoc;
  272.     PicHandle        drawPict;
  273.     Rect            drawRect;
  274.     short            fNum, i, lineInc, hCenter, picWidth, picHeight;
  275.     short            oldResFile;
  276.     FontInfo        fInfo;
  277.     Handle            iconHdl;
  278.     BitMap            iconBitMap;
  279.     Str255            pStr;
  280.     Point            where;
  281.     GrafPtr            curPort;
  282.  
  283. //    Preserve the current resource file in case we're printing.
  284.  
  285.     oldResFile = CurResFile();
  286.     windowDoc = MyGetDocPtr(whichWindow);
  287.  
  288. // Draw a red QuickDraw rectangle.
  289.  
  290.     ForeColor(redColor);
  291.     SetRect(&drawRect, 20, 20, 150, 150);
  292.     FrameRect(&drawRect);
  293.  
  294. // Draw a blue QuickDraw oval.
  295.  
  296.     ForeColor(blueColor);
  297.     OffsetRect(&drawRect, 40, 40);
  298.     FrameOval(&drawRect);
  299.  
  300. // Draw a black QuickDraw line with a 4x4 pen.
  301.  
  302.     ForeColor(blackColor);
  303.     PenSize(4, 4);
  304.     MoveTo(drawRect.left, drawRect.top);
  305.     LineTo(drawRect.right, drawRect.bottom);
  306.     PenSize(1, 1);
  307.  
  308. // Draw some QuickDraw text with various faces.
  309.  
  310.     GetFNum("\pNew York", &fNum);
  311.     TextFont(fNum);
  312.     TextSize(10);
  313.     GetFontInfo(&fInfo);
  314.     lineInc = fInfo.ascent + fInfo.leading + fInfo.descent;
  315.     TextFace(bold);
  316.     MoveTo(220, 40);
  317.     DrawString("\pFor Sale: ");
  318.     TextFace(0);
  319.     DrawString("\pEnglish sheepdog.  ");
  320.     TextFace(underline);
  321.     DrawString("\pCompletely");
  322.     TextFace(0);
  323.     MoveTo(220, 40 + lineInc);
  324.     DrawString("\phouse-broken, eats a lot, ");
  325.     TextFace(italic);
  326.     DrawString("\ploves cats and");
  327.     MoveTo(220, 40 + 2* lineInc);
  328.     DrawString("\psmall children.");
  329.     TextFace(0);
  330.     DrawString("\p  Free to a good home.");
  331.     MoveTo(220, 40 + 3* lineInc);
  332.  
  333. // Draw two concentric QuickDraw rectangles around the text we just drew.
  334.  
  335.     GetPen(&where);
  336.     drawRect.left = 216;
  337.     drawRect.top = 30;
  338.     drawRect.right = 450;
  339.     drawRect.bottom = where.v - lineInc/2;
  340.     FrameRect(&drawRect);
  341.     InsetRect(&drawRect, -2, -2);
  342.     FrameRect(&drawRect);
  343.  
  344. /*
  345.     Calculate the center of our window, and then draw a
  346.     QuickDraw picture at that location.
  347. */
  348.     hCenter = (whichWindow->portRect.right + whichWindow->portRect.left) >>1;
  349.  
  350.     UseResFile(gAppResRefNum);
  351.     drawPict = GetPicture(r_documentPict);
  352.     UseResFile(oldResFile);
  353.  
  354.     if (drawPict != nil) 
  355.     {
  356.         picWidth = (*drawPict)->picFrame.right - (*drawPict)->picFrame.left;
  357.         picHeight = (*drawPict)->picFrame.bottom - (*drawPict)->picFrame.top;
  358.         
  359.         drawRect.top = 240;
  360.         drawRect.left = hCenter -(picWidth >>1);
  361.         drawRect.bottom = drawRect.top + picHeight;
  362.         drawRect.right = drawRect.left + picWidth;
  363.          
  364.         DrawPicture(drawPict, &drawRect);
  365.         ReleaseResource((Handle) drawPict);
  366.     }
  367.  
  368. /*
  369.     Load a QuickDraw icon, and CopyBits a bunch of them across
  370.     the page, in various colors.
  371. */
  372.     UseResFile(gAppResRefNum);
  373.     iconHdl = (Handle) GetIcon(r_documentBitmap);
  374.     UseResFile(oldResFile);
  375.  
  376.     if (iconHdl != nil)
  377.     {
  378.         MoveHHi((Handle) iconHdl);
  379.         HLock((Handle) iconHdl);
  380.         iconBitMap.rowBytes = 4;
  381.         SetRect(&iconBitMap.bounds, 0, 0, 31, 31);
  382.         iconBitMap.baseAddr = *iconHdl;
  383.         
  384.         drawRect.top = drawRect.bottom +20;
  385.         drawRect.left = 10;
  386.         drawRect.bottom = drawRect.top +31;
  387.         drawRect.right = drawRect.left +31;
  388.         
  389.         for (i = 0; i < 12; i++)
  390.         {
  391.             switch (i % 6)
  392.             {
  393.                 case 0:
  394.                     ForeColor(blackColor);
  395.                     break;
  396.                 case 1:
  397.                     ForeColor(blueColor);
  398.                     break;
  399.                 case 2:
  400.                     ForeColor(greenColor);
  401.                     break;
  402.                 case 3:
  403.                     ForeColor(redColor);
  404.                     break;
  405.                 case 4:
  406.                     ForeColor(cyanColor);
  407.                     break;
  408.                 case 5:
  409.                     ForeColor(magentaColor);
  410.                     break;
  411.             }
  412.             
  413.             GetPort(&curPort);
  414.             CopyBits(&iconBitMap, &curPort->portBits, &iconBitMap.bounds, &drawRect, srcCopy, nil);
  415.     
  416.             drawRect.left  += 40;
  417.             drawRect.right += 40;
  418.         }
  419.         
  420.         ReleaseResource(iconHdl);
  421.     }
  422.  
  423. // Draw some more QuickDraw text.  This time, blue and 24 point.
  424.  
  425.     GetFNum("\pTimes", &fNum);
  426.     TextFont(fNum);
  427.     TextSize(24);
  428.     ForeColor(blueColor);
  429.     
  430.     // remove sprintf call, removes the need to link with the metrowerks ansi library
  431.     // was: pStr[0] = sprintf((char *) &pStr[1], "These are some typical QuickDraw objects");
  432.     
  433.     { 
  434.         unsigned char *tempStr = "\pThese are some typical QuickDraw objects" ;    // should come from a resource
  435.         BlockMove( &tempStr[1], &pStr[1], tempStr[0] ) ;
  436.         pStr[0] = tempStr[0] ;
  437.         
  438.  
  439.     }
  440.     
  441.     MoveTo(hCenter -(StringWidth(pStr) >>1), drawRect.bottom +20);
  442.     DrawString(pStr);
  443.  
  444. // Draw some QuickDraw PicComments.
  445.  
  446.     MyDrawPicComments();
  447.  
  448. /*
  449.     Draw some more black QuickDraw text in a different font
  450.     and size, indicating the page number.
  451. */
  452.     GetFNum("\pGeneva", &fNum);
  453.     TextFont(fNum);
  454.     TextSize(12);
  455.     
  456.     ForeColor(blackColor);
  457.     
  458.     
  459.     // remove sprintf call, removes the need to link with the metrowerks ansi library
  460.     // was: pStr[0] = sprintf((char *) &pStr[1], "This is page %ld of %ld.",
  461.     //                  windowDoc->curPage, windowDoc->numPages);
  462.  
  463.     {
  464.         unsigned char     *strPart1 = "\pThis is page " ;    // should come from a resource
  465.         unsigned char     *strPart2 = "\p of " ;            // should come from a resource
  466.         unsigned char    currentPage[32] ;
  467.         unsigned char    numberOfPages[32] ;
  468.         short    theLength = 0 ;
  469.         
  470.         NumToString( windowDoc->curPage, currentPage ) ;
  471.         NumToString( windowDoc->numPages, numberOfPages ) ;
  472.  
  473.         BlockMove( &strPart1[1], &pStr[theLength + 1], strPart1[0] ) ;
  474.         theLength += strPart1[0] ;
  475.         
  476.         BlockMove( ¤tPage[1], &pStr[theLength + 1], currentPage[0] ) ;
  477.         theLength += currentPage[0] ;
  478.         
  479.         BlockMove( &strPart2[1], &pStr[theLength + 1], strPart2[0] ) ;
  480.         theLength += strPart2[0] ;
  481.         
  482.         BlockMove( &numberOfPages[1], &pStr[theLength + 1], numberOfPages[0] ) ;
  483.         theLength += numberOfPages[0] ;
  484.         
  485.         pStr[0] = theLength ;
  486.         
  487.     }
  488.     MoveTo(hCenter -(StringWidth(pStr) >>1), drawRect.bottom +80);
  489.     DrawString(pStr);
  490. }
  491.  
  492.  
  493. /************************************************************
  494.   MyDrawPicComments - This routine just draws some example
  495.   PicComments which will make a PostScript device display
  496.   "This was drawn on a PostScript device." and other devices
  497.   display "This was drawn on a non-PostScript device."  We
  498.   use PostScriptBegin PostScriptEnd and PostScriptHandle.
  499.  
  500. *************************************************************/
  501.  
  502. void MyDrawPicComments()
  503. {
  504.     short        fNum;
  505.  
  506. /*
  507.     Draw some QuickDraw to set the PS clip, not necessary in
  508.     this case, but if we hadn't made any QuickDraw calls yet,
  509.     the PostScript clip wouldn't get set, and *everything*
  510.     would be clipped, at least on a non-GX system.  This code,
  511.     which doesn't actually draw anything, is here as a reminder.
  512. */
  513.  
  514.     PenSize(0, 0);
  515.     MoveTo(0, 0); 
  516.     Line(0, 0);
  517.     PenSize(1, 1);
  518.  
  519. /*
  520.     PostScriptBegin tells a PostScript driver to ignore Quickdraw
  521.     calls until it receives a PostScriptEnd picture comment.
  522.     This line is ignored by non-PostScript printer drivers.
  523. */
  524.  
  525.     PicComment(PostScriptBegin, 0, nil);
  526.  
  527. /*
  528.     QuickDraw representation. These calls will only be executed by
  529.     QuickDraw printers.  Set the font to Times Italic 14 pt and then
  530.     move and draw.
  531. */
  532.  
  533.     GetFNum("\pTimes", &fNum);
  534.     TextFont(fNum);
  535.     TextSize(14);
  536.     TextFace(italic);
  537.     MoveTo(127, 227);
  538.     DrawString("\pThis was drawn on a non-PostScript device.");
  539.     TextFace(0);
  540.  
  541. /*
  542.     PostScript representation. These calls will only be executed by
  543.     PostScript printers.  We draw the same as above, sans the "non-"
  544.     and shifted left a tad.
  545. */
  546.  
  547.     MySendPostScript("\p0 760 translate 1 -1 scale");
  548.     MySendPostScript("\p/Times-Italic findfont 14 scalefont setfont");
  549.     MySendPostScript("\p135 533 moveto (This was drawn on a PostScript device.) show");
  550.  
  551. /*
  552.     PostScriptEnd tells a PostScript driver to start executing
  553.     QuickDraw calls normally again.
  554. */
  555.  
  556.     PicComment(PostScriptEnd, 0, nil);
  557. }
  558.  
  559.  
  560. /************************************************************
  561.   MySendPostScript - This routine just packages the passed
  562.   Pascal string into a handle and sends the PostScriptHandle
  563.   PicComment.
  564.  
  565. *************************************************************/
  566.  
  567. void MySendPostScript(Str255 thePostScript)
  568. {
  569.     OSErr    err;
  570.     Handle    thePSHdl;
  571.     Ptr        thePSPtr;
  572.     long    textLen;
  573.  
  574. /*
  575.     Create a handle for the passed string plus a carriage
  576.     return.  Move the string's data into the handle, stuff a
  577.     carriage return on the end, call PicComment, and finally
  578.     dispose of the handle.
  579. */
  580.     textLen = thePostScript[0];
  581.     thePSHdl = TempNewHandle(textLen +1, &err);
  582.  
  583.     if (!err)
  584.     {
  585.         thePSPtr = *thePSHdl;
  586.         BlockMove(&thePostScript[1], thePSPtr, textLen);
  587.         *(thePSPtr +textLen) = (char) 13; //carriage return.
  588.         ++textLen;
  589.  
  590.         PicComment(PostScriptHandle, textLen, thePSHdl);
  591.         DisposHandle(thePSHdl);
  592.     }
  593. }
  594.  
  595.  
  596. /************************************************************
  597.   MyAdjustMenus - This routine enables and disables our
  598.   menus and menu items.
  599.  
  600. *************************************************************/
  601.  
  602. void MyAdjustMenus()
  603. {
  604.     WindowPtr        activeWindow;
  605.     MenuHandle        appleMenu, fileMenu, editMenu, documentMenu;
  606.     MyDocumentPtr    activeDocument;
  607.     Boolean            docOpen, onFirstPage, onLastPage, maxPages, neverSaved;
  608.  
  609. /*
  610.     If we're in a GX printing dialog, don't adjust our
  611.     menus.  We've already done that.  Otherwise, enable our menus.
  612. */
  613.     if (gInPrintDialog) return;
  614.  
  615.     appleMenu = GetMHandle(mApple);
  616.     editMenu = GetMHandle(mEdit);
  617.     fileMenu = GetMHandle(mFile);
  618.     documentMenu = GetMHandle(mDocument);
  619.  
  620.     EnableItem(appleMenu, iAbout);
  621.     EnableItem(fileMenu,  iQuit);
  622.     EnableItem(fileMenu,  iNew);
  623.     EnableItem(fileMenu,  iOpen);
  624.  
  625. /*
  626.     If we have a document open, we enable certain menu items.
  627.     Otherwise, we don't.
  628. */
  629.  
  630.     activeWindow = FrontWindow();
  631.  
  632.     if (activeWindow)
  633.     {
  634.         if (((WindowPeek) activeWindow)->windowKind != userKind)
  635.             activeWindow = nil;
  636.     }
  637.  
  638.     docOpen = (activeWindow != nil);
  639.  
  640.     if (!docOpen)                                        // No document open.
  641.     {
  642.         if (gGXIsPresent)                        // Using QuickDraw GX.
  643.         {
  644.             DisableItem(fileMenu, iPrintOneCopy);
  645.             DisableItem(fileMenu, iCustomPageSetup);
  646.             DisableItem(fileMenu, iPrint);
  647.         }
  648.         else                                    // This disables "Print" in non-GX File menu.
  649.             DisableItem(fileMenu, iPrint -1);
  650.  
  651.         DisableItem(fileMenu, iClose);
  652.         DisableItem(fileMenu, iSave);
  653.         DisableItem(fileMenu, iSaveAs);
  654.         DisableItem(fileMenu, iPageSetup);
  655.         DisableItem(documentMenu, iInsertPage);
  656.         DisableItem(documentMenu, iDeletePage);
  657.         DisableItem(documentMenu, iAheadPage);
  658.         DisableItem(documentMenu, iBackPage);
  659.     }
  660.     else                                                // A document is open.
  661.     {
  662.         if (gGXIsPresent)                        // Using QuickDraw GX.
  663.         {
  664.             EnableItem(fileMenu, iPrintOneCopy);
  665.             EnableItem(fileMenu, iCustomPageSetup);
  666.             EnableItem(fileMenu, iPrint);
  667.         }
  668.         else                                    // This enables "Print" in non-GX File menu.
  669.             EnableItem(fileMenu, iPrint -1);
  670.  
  671.         EnableItem(fileMenu, iClose);
  672.         EnableItem(fileMenu, iPageSetup);
  673.         EnableItem(fileMenu, iSaveAs);
  674.  
  675. /*
  676.     Enable/disable items based on the number of pages in our document,
  677.     whether we're on the first or last page, and whether or not it's
  678.     been saved yet.
  679. */
  680.         activeDocument = MyGetDocPtr(activeWindow);
  681.  
  682.         if (activeDocument->numPages > 1)                // Got at least one page?
  683.             EnableItem(documentMenu, iDeletePage);
  684.         else
  685.             DisableItem(documentMenu, iDeletePage);
  686.  
  687.         onFirstPage = (activeDocument->curPage == 1);
  688.         onLastPage = (activeDocument->curPage == activeDocument->numPages);
  689.         maxPages = (activeDocument->numPages == kMaxPages);
  690.         neverSaved = (activeDocument->documentFSSpec.name[0] == 0);
  691.  
  692.         if (neverSaved)                                    // Never saved this document?
  693.             DisableItem(fileMenu, iSave);
  694.         else
  695.             EnableItem(fileMenu, iSave);
  696.  
  697.         if (!maxPages)                                    // Can still add more pages?
  698.             EnableItem(documentMenu, iInsertPage);
  699.         else
  700.             DisableItem(documentMenu, iInsertPage);
  701.  
  702.         if (!onLastPage)                                // Not on last page?
  703.             EnableItem(documentMenu, iAheadPage);
  704.         else
  705.             DisableItem(documentMenu, iAheadPage);
  706.  
  707.         if (!onFirstPage)                                // Not on first page?
  708.             EnableItem(documentMenu, iBackPage);
  709.         else
  710.             DisableItem(documentMenu, iBackPage);
  711.     }
  712. }
  713.  
  714.  
  715. /************************************************************
  716.   MyAdjustMenusForPrintDialogs - This routine handles
  717.   enabling and disabling menu items when we're putting up
  718.   or tearing down QuickDraw GX movable modal print dialogs.
  719.  
  720. *************************************************************/
  721.  
  722. void MyAdjustMenusForPrintDialogs(Boolean dialogGoingUp)
  723. {
  724.     MenuHandle    appleMenu, fileMenu, editMenu, documentMenu;
  725.  
  726.     appleMenu = GetMHandle(mApple);
  727.     fileMenu = GetMHandle(mFile);
  728.     editMenu = GetMHandle(mEdit);
  729.     documentMenu = GetMHandle(mDocument);
  730.  
  731. /*
  732.     If a print dialog is about to be displayed, disable our
  733.     "About" item, our File menu, and our Document menu.
  734.     Otherwise, enable them since a print dialog just came down.
  735. */
  736.     if (dialogGoingUp)
  737.     {
  738.         DisableItem(appleMenu, iAbout);
  739.         DisableItem(fileMenu, 0);
  740.         DisableItem(documentMenu, 0);
  741.         HiliteMenu(0);
  742.     }
  743.     else
  744.     {
  745.         EnableItem(appleMenu, iAbout);
  746.         EnableItem(fileMenu, 0);
  747.         DisableItem(editMenu, 0);            // *Sigh!*  Our app's lazy.
  748.         EnableItem(documentMenu, 0);
  749.     }
  750.  
  751.     DrawMenuBar();
  752.     gInPrintDialog = dialogGoingUp;
  753. }
  754.  
  755.  
  756. /************************************************************
  757.   MyDoMenuCommand - This routine handles the dispatching of
  758.   our menu requests.
  759.  
  760. *************************************************************/
  761.  
  762. void MyDoMenuCommand(long menuResult)
  763. {
  764.     short                menuID, menuItem;
  765.     long                curPage, numPages, newPage;
  766.     Str255                daName;
  767.     OSErr                err;
  768.     WindowPtr            activeWindow;
  769.     MyDocumentPtr        activeDocument, aDocument;
  770.  
  771.     menuID = menuResult >>16;
  772.     menuItem = menuResult & 0x0000FFFF;
  773.     activeWindow = FrontWindow();
  774.     activeDocument = MyGetDocPtr(activeWindow);
  775.  
  776. /*
  777.     Because we delete two items from our File menu if we're not
  778.     using QuickDraw GX, we may need to convert the menu item
  779.     before servicing it.  MyConvertMenuItem handles this.
  780. */
  781.     MyConvertMenuItem(&menuID, &menuItem);
  782.  
  783.     switch (menuID)
  784.     {
  785.         case mApple:
  786.             switch (menuItem)
  787.             {
  788.                 case iAbout:                    // About.
  789.  
  790.                     Alert(r_About, nil);
  791.                     break;
  792.                 
  793.                 default:                        // DAs, etc.
  794.  
  795.                     GetItem(GetMHandle(mApple), menuItem, daName);
  796.                     OpenDeskAcc(daName);
  797.                     break;
  798.             }
  799.             break;
  800.             
  801.             case mFile:
  802.                 switch (menuItem)
  803.                 {                        
  804.                     case iNew:                    // New or Open.
  805.                     case iOpen:
  806.  
  807.                         err = MyCreateDocument(kDefaultTitle, &aDocument);
  808.  
  809.                         if ((err == noErr) && (menuItem == iOpen))
  810.                         {
  811.                             err = MyLoadDocument(aDocument);
  812.  
  813.                             if (err != noErr)
  814.                                 MyDisposeDocument(aDocument);
  815.                         }
  816.                         
  817.                         if (err == noErr)
  818.                         {
  819.                             ShowWindow(aDocument->documentWindow);
  820.                             SelectWindow(aDocument->documentWindow);
  821.                             MyAdjustMenus();
  822.                         }
  823.                         break;
  824.                                                 
  825.                     case iClose:                // Close.
  826.  
  827.                         MyDisposeDocument(activeDocument);
  828.                         break;
  829.                                                 
  830.                     case iSave:                    // Save or Save As.
  831.                     case iSaveAs:
  832.  
  833.                         err = MySaveDocument(activeDocument, (menuItem == iSaveAs));
  834.                         break;
  835.         
  836.                     case iPageSetup:            // Page Setup.
  837.  
  838.                         if (MyDoPageSetup(activeDocument))
  839.                             MyRepaginateDoc(activeDocument);
  840.                         break;
  841.  
  842.                     case iCustomPageSetup:        // Custom Page Setup (only with GX).
  843.  
  844.                         if (MyDoCustomPageSetup(activeDocument))
  845.                             MyRepaginateDoc(activeDocument);
  846.                         break;
  847.  
  848.                     case iPrint:                // Print.
  849.  
  850.                         err = MyPrintDocument(activeDocument);
  851.                         break;
  852.  
  853.                     case iPrintOneCopy:            // Print one copy (only with GX).
  854.  
  855.                         err = MyPrintOneCopy(activeDocument);
  856.                         break;
  857.  
  858.                     case iQuit:                    // Quitting.
  859.  
  860.                         gQuitting = true;
  861.                         break;
  862.                 }
  863.                 break;
  864.                 
  865.             case mEdit:  // If this were a real app, blah, blah, blah.
  866.                 break;
  867.                 
  868.             case mDocument:
  869.                 switch (menuItem)
  870.                 {                        
  871.                     case iInsertPage:            // Insert a page.
  872.                             
  873.                             newPage = activeDocument->curPage;
  874.                             MyInsertPage(activeDocument, &newPage);
  875.                             activeDocument->curPage = newPage;
  876.                             SetPort(activeWindow);
  877.                             EraseRect(&activeWindow->portRect);
  878.                             InvalRect(&activeWindow->portRect);
  879.                         break;
  880.                                                 
  881.                     case iDeletePage:            // Delete current page.
  882.                             
  883.                             curPage = activeDocument->curPage;
  884.                             numPages = activeDocument->numPages;
  885.  
  886.                             if (numPages > 1)
  887.                             {
  888.                                 MyDisposePage(activeDocument, curPage);
  889.  
  890.                                 if (curPage == numPages)
  891.                                     curPage = --activeDocument->curPage;
  892.                                 
  893.                                 SetPort(activeWindow);
  894.                                 EraseRect(&activeWindow->portRect);
  895.                                 InvalRect(&activeWindow->portRect);
  896.                             }
  897.                         break;
  898.                                                 
  899.                     case iAheadPage:            // Display ahead one page.
  900.                             
  901.                             curPage = activeDocument->curPage;
  902.                             numPages = activeDocument->numPages;
  903.  
  904.                             if (curPage < numPages)
  905.                             {
  906.                                 ++activeDocument->curPage;
  907.                                 
  908.                                 SetPort(activeWindow);
  909.                                 EraseRect(&activeWindow->portRect);
  910.                                 InvalRect(&activeWindow->portRect);
  911.                             }
  912.                         break;
  913.                                                 
  914.                     case iBackPage:                // Display back one page.
  915.                             
  916.                             curPage = activeDocument->curPage;
  917.  
  918.                             if (curPage > 1)
  919.                             {
  920.                                 --activeDocument->curPage;
  921.                                 
  922.                                 SetPort(activeWindow);
  923.                                 EraseRect(&activeWindow->portRect);
  924.                                 InvalRect(&activeWindow->portRect);
  925.                             }
  926.                         break;
  927.                 }
  928.                 break;
  929.     }
  930.  
  931.     HiliteMenu(0);
  932. }
  933.  
  934.  
  935. /************************************************************
  936.   MyConvertMenuItem - This routine converts our menu item
  937.   IDs, if we aren't running QuickDraw GX.  Since our
  938.   MyDoMenuCommand routine switches off of the QuickDraw GX
  939.   menu IDs, we may need to adjust them.  (Remember, when
  940.   QuickDraw GX is not running we remove the "Print One Copy"
  941.   and "Custom Page Setup" menu items.
  942.  
  943. *************************************************************/
  944.  
  945. void MyConvertMenuItem(short *menuID, short *menuItem)
  946. {
  947.     if (!gGXIsPresent)                        // QuickDraw GX isn't running?
  948.     {                                        // then…
  949.         if (*menuItem == iCustomPageSetup)    // If "Custom Page Setup" is selected,
  950.             *menuItem = iPrint;                // it's really "Print."
  951.         else                                // and…
  952.             if (*menuItem == iPrintOneCopy)    // If "Print One Copy" is selected,
  953.                 *menuItem = iQuit;            // it's really "Quit."
  954.     }
  955. }
  956.  
  957.  
  958. /************************************************************
  959.   MyGetDocPtr - This routine returns a pointer to the
  960.   private document structure our application attaches to
  961.   its windows.
  962.  
  963. *************************************************************/
  964.  
  965. MyDocumentPtr MyGetDocPtr(WindowPtr whichWindow)
  966. {
  967.     MyDocumentPtr    windowsDocument = nil;
  968.  
  969.     if (whichWindow != nil)
  970.         windowsDocument = (MyDocumentPtr) GetWRefCon(whichWindow);
  971.  
  972.     return windowsDocument;
  973. }
  974.  
  975.